
#pragma once

#include <list>
#include <bitset>
#include <cmath>
#include "../common/basetypes.h"

namespace LGFun
{

typedef UInt32 PrimeNum;

/* Add a task to EratosteneSiege*/
/*This task is execute when a new prime number is found.*/
class AtPrimeNumberTask
{
public:
    /*If it return false, stop the EratosteneSiege computation.*/
    /*i_number is a new prime number. In ascendent order.*/
    virtual bool Update(const PrimeNum i_number) = 0; //ugasoft: added const to remove warning
    /*Reset the state of the class.*/
    /*It is called before the prime number computation.*/
    virtual void Reset() = 0;
};


/*
Compute the prime number with in a range.
Require more memory space but it may be parallelized.
*/
class EratosteneSieve
{
public:
    typedef std::list<PrimeNum> PrimeList;
    typedef PrimeList::iterator ListIterator;


    explicit EratosteneSieve(UInt32 i_maxNum);
    EratosteneSieve(const EratosteneSieve& i_other);
    ~EratosteneSieve();

    EratosteneSieve& operator=(const EratosteneSieve& i_other); //ugasoft: I supposed this was an operator= and not an operator==...

    bool AddPerPrimeNumTask(AtPrimeNumberTask* i_task);
    void Compute();
    bool IsPrime(UInt32 i_number) const;

private:
    bool* m_sieve; // A bit set may be better.
    AtPrimeNumberTask* m_ppTask;
    UInt32 m_size;
};



// TASK OBJECTS



//Count the numbers founded.
class PrimeNumCount : public AtPrimeNumberTask
{
public: 
    PrimeNumCount() :
      m_count(0)
      {}

    bool Update(const PrimeNum /*i_number*/) // ugasoft: commented out unused parameter and added a "const" qualifier to remove warning 
    {
        ++m_count;
        return true;
    }

    void Reset()
    {
        m_count = 0;
    }

    UInt32 GetCount() const
    {
        return m_count;
    }
protected:
    UInt32 m_count;
};



//Sum the prime numbers founded. For problem 10.
class PrimeNumSum : public AtPrimeNumberTask
{
public:
    PrimeNumSum() :
      m_sum(0)
      {}

    bool Update(const PrimeNum i_number)
    {
        m_sum += i_number;
        return true;
    }

    void Reset()
    {
        m_sum = 0;
    }

    UInt64 GetSum()
    {
        return m_sum;
    }

protected:
    UInt64 m_sum;
};



//Get the n^th prime number. For problem 7.
class NPrimeNum : public PrimeNumCount
{
public:
    NPrimeNum(UInt32 i_requered) :
      PrimeNumCount(),
      m_requrired(i_requered)
      {}

    bool Update(const PrimeNum i_number)
    {
        PrimeNumCount::Update(i_number);
        if(PrimeNumCount::m_count == m_requrired)
        {
            m_nPrime = i_number;
            return false;
        }
        return true;
    }

    void Reset()
    {
        PrimeNumCount::Reset();
        m_nPrime = 0;
    }

    PrimeNum GetNPrimeNum()
    {
        return m_nPrime;
    }

protected:
    PrimeNum m_nPrime;
    UInt32 m_requrired;
};


// Store the prime numbers found.
class PrimeNumCollector : public AtPrimeNumberTask
{
public:
    bool Update(const PrimeNum i_number)
    {
        m_list.push_back(i_number);
    }

    void Reset()
    {
        m_list.clear();
    }


    EratosteneSieve::PrimeList& GetList()
    {
        return m_list;
    }

protected:
    EratosteneSieve::PrimeList m_list;
};


}
